#include "stdio.h"
#include "queue.h"
#include "keyboard.h"
#include "console.h"
#include "kernel.h"
#include "stdarg.h"
#include "ctype.h"
#include "video.h"
#include "scheduler.h"
#include "shell.h"
#include "stdlib.h"
#include "libasm.h"
#include "string.h"
#include "history.h"

static void handle_special_key(int key, consoleT *c);
static void handle_normal_key(int key, consoleT *c);

int
getchar(void)
{
	keyT key = {0};
	consoleT *cons;
	bufferT *buf;
	int c;

	/* Obtengo la consola actual */
	cons = get_console_by_index(get_task_tty(0));

	buf = &(cons->b);

	/* Si hay algo en el arreglo de caracteres, lo retorno. */
	if (buf->dim == buf->begin)
	{
		/* Resetear la cola e ir al while para pedir un caracter */
		buf->begin = buf->dim = buf->pos = 0;
	}
	else if (buf->dim != 0)
	{
		c = buf->vec[buf->begin];
		buf->begin++;
		return (int)c;
	}

	/* Si llegamos a este punto es porque el buffer esta vacio
	 * y tenemos que bloquearnos hasta que el usuario ingrese
	 * un \n o se llene el buffer de consola */

	/* Voy esperando scancodes */
	while ( (key.value != '\n') && (buf->dim != BUFFER_LENGTH))
	{
		/* Leo una tecla del tty actual */
		key = get_key();

		/* Si no hay nada sigo esperando */
		//if(key.value == EOF)
			//puts("EOF");
		if (key.value != KEY_NULL)
		{
			/* Hago lo que tenga que hacer con la tecla */
			if (key.value >= 0)
			{
				handle_normal_key(key.value, cons);
			}
			else
			{
				handle_special_key(key.value, cons);
			}

		}
		else
			set_status(BLOCKED);
	}

	/* Se invoca a si misma una sola vez, cuando termina de juntar caracteres y
	 * debe empezar a retornarlos */
	return getchar();
}

int
putchar(int c)
{
	int cursor;
	int ctty;
	videoT *v;
	_Cli();
	ctty = get_task_tty(0);

	/* Obtengo el objeto de video actual */
	v = get_console_video(ctty);

	/* Obtengo la posicion del cursor de la consola activa */
	cursor = get_cursor_pos(v);

	if(is_bkg_task(get_task_pid(NULL)))
	{
		_Sti();
		return c;
	}
	
	/* Escribo en la posicion actual */
	if (c == '\n')
	{
		/* Si estoy en la ultima linea lo mando al principio */
		if ( cursor / LINE_LENGTH == LAST_LINE - 1 )
			scroll_screen(v);

		/* Avanzo a la proxima linea */
		next_line(v);
	}
	else
	{
		/* Escribo el caracter tal cual me llego */
		write_video(v, (char)c, WHITE_TXT);

		set_cursor_pos(v, cursor + 1);

		/* Me fijo si me pase de el rango visible */
		if ( ++cursor >= LINE_LENGTH * LAST_LINE )
			scroll_screen(v);
	}

	_Sti();

	return c;
}


int
puts(const char *s)
{
	return printf("%s", s);
}

int
getsn(char *s, unsigned int n)
{
	unsigned int i;
	int c;

	n--; //espacio null character final
	for (i = 0; i < n && (c = getchar()) != EOF && c != '\n'; i++)
		s[i] = c;

	s[i] = '\0';
	while (c != '\n' && c != EOF)
		c = getchar();

	return i;
}


int
getint(void)
{
	char buffer[16];

	getsn(buffer, 16);

	return atoi(buffer);
}

static void
handle_normal_key(int key, consoleT *console)
{
	int i;

	/* Si es un caracter imprimible */
	if ( isprint(key) || key == '\n' )
		buffer_insert(console, key);
	else
	{
		if (key == '\b')
		{
			buffer_delete(console);
		}
		else if (key == '\t')
		{
			for (i=0; i<5; i++)
				handle_normal_key(' ', console);
		}
	}
}



static void
handle_special_key(int key, consoleT *console)
{
	videoT *v;
	char aux[SHELL_CMD_BUFFER_SIZE]={0};
	int oldpos, i=0, len, arrow=0;
	oldpos = console->b.pos;

	v = &(console->v);

	if (key == KEY_LEFT)
	{
		if (console->b.pos != 0)
			console->b.pos--;
	}
	else if (key == KEY_RIGHT)
	{
		if (console->b.pos != console->b.dim)
			console->b.pos++;
	}
	else if(key == KEY_UP)
	{
		arrow=1;

		for(i=0; i<SHELL_CMD_BUFFER_SIZE; i++)
			handle_normal_key('\b', console);
		console->b.pos = 0;
		console->b.dim = 0;
		console->b.begin = 0;
		strcpy(aux, flechaParaArriba(get_active_tty_num()));
		len = strlen(aux);
		for(i=0; i<len; i++)
			buffer_insert(console, aux[i]);
	}
	else if(key == KEY_DOWN)
	{
		arrow=1;
		for(i=0; i<SHELL_CMD_BUFFER_SIZE; i++)
			handle_normal_key('\b', console);
		console->b.pos = 0;
		console->b.dim = 0;
		console->b.begin = 0;
		strcpy(aux, flechaParaAbajo(get_active_tty_num()));
		len = strlen(aux);
		for(i=0; i<len; i++)
			buffer_insert(console, aux[i]);
	}
	else if (key == KEY_HOME)
		console->b.pos = 0;
	else if (key == KEY_END)
		console->b.pos = console->b.dim;
	else if (key == KEY_DELETE)
	{
		if (console->b.pos == console->b.dim || console->b.dim == 0)
			return;

		console->b.pos++;
		set_cursor_pos(&(console->v), console->v.cursor + 1);
		buffer_delete(console);
	}

	if(arrow==0) //esto se hace solo si no se apreto flechaParaArriba o flechaParaAbajo
		set_cursor_pos(&(console->v), console->v.cursor - oldpos + console->b.pos);

	return;
}

int
print_int(int num)
{
	char buffer[12];
	int i, sum;

	sum = (num < 0) ? 1 : 0;
	i = 0;
	do
	{
		buffer[i++] = (num % 10) + '0';
		num /= 10;
	} while (num != 0);

	if (sum)
		putchar('-');

	sum += i;
	while (i > 0)
		putchar(buffer[--i]);

	return (sum);
}

